#pragma once

#include <iostream>
#include <string>
#include <cstdio>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "Log.hpp"
#include "Common.hpp"

using namespace LogModule;

const std::string dev = "/dev/null";

// 将服务进行守护进程化的服务
void Deamon(int nochdir, int noclose)
{
	// 1. 忽略IO，子进程退出等相关信号
	signal(SIGPIPE, SIG_IGN); // 13 -- 在进程尝试向一个已关闭的管道或套接字写入数据时发送
	signal(SIGCHLD, SIG_IGN); // 17 -- 在子进程状态改变时发送（如终止、暂停或恢复）

	// 2. 父进程直接结束
	if(fork() > 0)
		exit(0);

	// 3. 只能是子进程，孤儿了，父进程就是1
	setsid();// 成为一个独立会话

	if(nochdir == 0) // 更改进程的工作路径
		chdir("/");//防止当前工作目录所在的文件系统被挂载，
		//从而影响系统正常运行或导致守护进程运行出现问题
	
    // 4. 依旧可能显示器，键盘，stdin，stdout， stderr关联的
	// 守护进程，不从键盘输入，也不需要向显示器打印
	// 方法1：关闭0，1，2 -- 不推荐
	// 方法2：打开/dev/null，重定向标准输入，标准输出，标准错误到/dev/null
	if(noclose == 0)
	{
		//以读写模式打开/dev/null设备文件
		int fd = ::open(dev.c_str(), O_RDWR);
		if(fd < 0)
		{
			LOG(LogLevel::FATAL) << "open " << dev << " errno";
			exit(1);
		}
		else
		{
			//使用dup2函数将文件描述符 0、1、2 都复制为fd
			dup2(fd, 0);
			dup2(fd, 1);
			dup2(fd, 2);
			close(fd);
		}
	}
}